package com.database.findmystuff;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Set;
import java.io.*;

import android.content.Context;
import android.util.Log;

public class DB implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 121595181924303021L;
	private  HashMap<User, LinkedList<Item>> itemDB;
	private  HashMap<String, User> userDB;
	transient protected Context c;
	/**
	 * The constructor that makes the hashmaps when the class is called the first time
	 */
	public DB(Context c){
		itemDB = new HashMap<User, LinkedList<Item>>();
		setUserDB(new HashMap<String, User>());
		this.c=c;
	}
	/**
	 * this is a constructor in case the user wants to get the DB a set of DBs
	 * @param itemDB the item database
	 * @param userDB the user database
	 * @param c the context of the app
	 */
	public DB(HashMap<User, LinkedList<Item>> itemDB, HashMap<String, User> userDB, Context c){
		this.itemDB=itemDB;
		this.setUserDB(userDB);
		this.c = c;
	}
	
	public void putDB(HashMap<User, LinkedList<Item>> itemDB1, HashMap<String, User> userDB1){
		this.itemDB=itemDB1;
		this.setUserDB(userDB1);
	}

	/**
	 * Creates a new User of the Class Type User
	 * 
	 * @param newUser The user being created
	 */

	public void createUser(User newUser){
		if(itemDB.containsKey(newUser)==true){
			System.out.println("User Already Exists");
		}else{
			itemDB.put(newUser, null);
			getUserDB().put(newUser.getEmail(), newUser);
			Log.v("loginAttempt", "Account created successfully!");
		}
	}
	/**
	 * used to set the isAdmin field for users in both databases
	 * @param email the email of the user
	 * @param isAdmin the bool for if they are admin or not
	 */
	public void setIsAdmin(String email, boolean isAdmin){
		User user = getUser(email);
		User user2 = user;
		LinkedList<Item> temp = getItemList(user2);
		Iterator<User> it =itemDB.keySet().iterator();
		while(it.hasNext()){
			if(it.next().hashCode()==user.hashCode()){
				it.remove();
			}
		}
		user.setIsAdmin(isAdmin);
		user2=user;
		itemDB.put(user2, temp);
	}
	/**
	 * Checks to see if the user is in the database and if their username and password are correct
	 * @param userName the email of the user
	 * @param password the password of the user
	 * @return true if the login check is good and false otherwise
	 */
	public Boolean checkLogin(String userName, String password){
		Set<User> userList=this.getUserList();
		for(User u:userList){
			if(userName.equals(u.getEmail())){
    			if(password.equals(u.getPassword())){
    					return true;
    				}
    			else{
    				System.out.println("Incorrect Password");
    				int temp = u.getAttemptCounter();
    				temp--;
    				u.setAttemptCounter(temp);
    				return false;
    			}
			}
			else{
				System.out.println("User Does Not Exist");
				return false;
			}
		}
		return false;
	}

	/**
	 * Creates an Item using the current user as the key.
	 * 
	 * @param currentUser The unique ID for the item being created.
	 * @param newItem The new Item being created.
	 */
	public void createItem(User currentUser, Item newItem){
		if(itemDB.containsKey(currentUser)==true){
			if(itemDB.get(currentUser)==null){
				LinkedList<Item> itemlist;
				itemlist=new LinkedList<Item>();
				itemlist.add(newItem);
				itemDB.put(currentUser,itemlist);
			}else{
				itemDB.get(currentUser).addLast(newItem);
			}
			System.out.print("Something's wrong");
		}	

	}

	/**
	 * Returns a linked list of Items to be output for a user
	 * 
	 * @param currentUser User trying to access their itemList
	 * @return Linked list of items in a hashtable
	 */
	public LinkedList<Item> getItemList(User currentUser){
		return itemDB.get(currentUser);
	}

	/**
	 * Used to get the list of users in the item database 
	 * 
	 * @return The set of all users that have items in the database
	 */
	public Set<User> getUserList(){
		return itemDB.keySet();
	}

	/**
	 * Used to get a list of all users in the user database
	 * 
	 * @param email The key used to find the user object that it relates to.
	 * @return A specific user for independent login and other single user account actions
	 */
	public User getUser(String email){
		return getUserDB().get(email);
	}
	/**
	 * @return the userDB
	 */
	public HashMap<String, User> getUserDB() {
		return userDB;
	}
	/**
	 * @param userDB the userDB to set
	 */
	public void setUserDB(HashMap<String, User> userDB) {
		this.userDB = userDB;
	}
	/**
	 * Deletes the user specified
	 * @param username the user that is to be deleted.
	 */
	public boolean delete(User username){
		if(getUserDB().containsKey(username.getEmail())){
			getUserDB().remove(username);
			if(itemDB.containsKey(username)){ 
				itemDB.remove(username);
				return true;
			}	
		}	
		return false;
	}
	
	public void saveObject(DB db){
		c.deleteFile("userDB");
		c.deleteFile("itemDB");
        try
        {
           ObjectOutputStream oos = new ObjectOutputStream(c.openFileOutput("userDB.txt", Context.MODE_PRIVATE)); //Select where you wish to save the file...
           oos.writeObject(db.getUserDB()); // write the class as an 'object'
           oos.flush(); // flush the stream to insure all of the information was written to 'DB.TXT'
           oos.close();// close the stream
        }
        catch(Exception ex)
        {
           Log.v("Serialization Save Error : ",ex.getMessage());
           ex.printStackTrace();
        }
        
        try
        {
           ObjectOutputStream oos = new ObjectOutputStream(c.openFileOutput("itemDB.txt", Context.MODE_PRIVATE)); //Select where you wish to save the file...
           oos.writeObject(db.itemDB); // write the class as an 'object'
           oos.flush(); // flush the stream to insure all of the information was written to 'DB.TXT'
           oos.close();// close the stream
        }
        catch(Exception ex)
        {
           Log.v("Serialization Save Error : ",ex.getMessage());
           ex.printStackTrace();
        }
   }
    
   @SuppressWarnings("unchecked")
public DB loadSerializedObject(DB db)
   {
       try
       {
           ObjectInputStream ois = new ObjectInputStream(c.openFileInput("userDB.txt"));
           db.setUserDB((HashMap<String, User>) ois.readObject());
       }
       catch(Exception ex)
       {
       Log.v("Serialization Read Error : ",ex.getMessage());
           ex.printStackTrace();
       }
       try
       {
           ObjectInputStream ois = new ObjectInputStream(c.openFileInput("itemDB.txt"));
           db.itemDB = (HashMap<User, LinkedList<Item>>) ois.readObject();
       }
       catch(Exception ex)
       {
       Log.v("Serialization Read Error : ",ex.getMessage());
           ex.printStackTrace();
       }
       return db;
   }
}